<template><div><h2 id="授权" tabindex="-1"><a class="header-anchor" href="#授权"><span>授权</span></a></h2>
<p>授权是指验证用户是否允许做某件事的过程。Yii 提供两种授权方法：存取控制过滤器（ACF）和基于角色的存取控制（RBAC）。</p>
<h2 id="存取控制过滤器" tabindex="-1"><a class="header-anchor" href="#存取控制过滤器"><span>存取控制过滤器</span></a></h2>
<p>存取控制过滤器（ACF）是一种通过 <code v-pre>yii\filters\AccessControl</code> 类来实现的简单授权方法， 非常适用于仅需要简单的存取控制的应用。正如其名称所指，ACF 是一种动作过滤器 <a href="https://github.com/yiisoft/yii2/blob/master/docs/guide-zh-CN/structure-filters.md" target="_blank" rel="noopener noreferrer">filter</a>，可在控制器或者模块中使用。当一个用户请求一个动作时，ACF 会检查 <code v-pre>yii\filters\AccessControl::rules</code> 列表，判断该用户是否允许执 行所请求的动作。</p>
<p>下述代码展示如何在 <code v-pre>site</code> 控制器中使用 ACF：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">yii<span class="token punctuation">\</span>web<span class="token punctuation">\</span>Controller</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">yii<span class="token punctuation">\</span>filters<span class="token punctuation">\</span>AccessControl</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">class</span> <span class="token class-name-definition class-name">SiteController</span> <span class="token keyword">extends</span> <span class="token class-name">Controller</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">behaviors</span><span class="token punctuation">(</span><span class="token punctuation">)</span></span>
<span class="line">    <span class="token punctuation">{</span></span>
<span class="line">        <span class="token keyword">return</span> <span class="token punctuation">[</span></span>
<span class="line">            <span class="token string single-quoted-string">'access'</span> <span class="token operator">=></span> <span class="token punctuation">[</span></span>
<span class="line">                <span class="token string single-quoted-string">'class'</span> <span class="token operator">=></span> <span class="token class-name static-context">AccessControl</span><span class="token operator">::</span><span class="token keyword">class</span><span class="token punctuation">,</span></span>
<span class="line">                <span class="token string single-quoted-string">'only'</span> <span class="token operator">=></span> <span class="token punctuation">[</span><span class="token string single-quoted-string">'login'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'logout'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'signup'</span><span class="token punctuation">]</span><span class="token punctuation">,</span></span>
<span class="line">                <span class="token string single-quoted-string">'rules'</span> <span class="token operator">=></span> <span class="token punctuation">[</span></span>
<span class="line">                    <span class="token punctuation">[</span></span>
<span class="line">                        <span class="token string single-quoted-string">'allow'</span> <span class="token operator">=></span> <span class="token constant boolean">true</span><span class="token punctuation">,</span></span>
<span class="line">                        <span class="token string single-quoted-string">'actions'</span> <span class="token operator">=></span> <span class="token punctuation">[</span><span class="token string single-quoted-string">'login'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'signup'</span><span class="token punctuation">]</span><span class="token punctuation">,</span></span>
<span class="line">                        <span class="token string single-quoted-string">'roles'</span> <span class="token operator">=></span> <span class="token punctuation">[</span><span class="token string single-quoted-string">'?'</span><span class="token punctuation">]</span><span class="token punctuation">,</span></span>
<span class="line">                    <span class="token punctuation">]</span><span class="token punctuation">,</span></span>
<span class="line">                    <span class="token punctuation">[</span></span>
<span class="line">                        <span class="token string single-quoted-string">'allow'</span> <span class="token operator">=></span> <span class="token constant boolean">true</span><span class="token punctuation">,</span></span>
<span class="line">                        <span class="token string single-quoted-string">'actions'</span> <span class="token operator">=></span> <span class="token punctuation">[</span><span class="token string single-quoted-string">'logout'</span><span class="token punctuation">]</span><span class="token punctuation">,</span></span>
<span class="line">                        <span class="token string single-quoted-string">'roles'</span> <span class="token operator">=></span> <span class="token punctuation">[</span><span class="token string single-quoted-string">'@'</span><span class="token punctuation">]</span><span class="token punctuation">,</span></span>
<span class="line">                    <span class="token punctuation">]</span><span class="token punctuation">,</span></span>
<span class="line">                <span class="token punctuation">]</span><span class="token punctuation">,</span></span>
<span class="line">            <span class="token punctuation">]</span><span class="token punctuation">,</span></span>
<span class="line">        <span class="token punctuation">]</span><span class="token punctuation">;</span></span>
<span class="line">    <span class="token punctuation">}</span></span>
<span class="line">    <span class="token comment">// ...</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>上面的代码中 ACF 以行为 (behavior) 的形式附加到 <code v-pre>site</code> 控制器。 这就是很典型的使用行动过滤器的方法。 <code v-pre>only</code> 选项指明 ACF 应当只 对 <code v-pre>login</code>， <code v-pre>logout</code> 和 <code v-pre>signup</code> 方法起作用。所有其它的 <code v-pre>site</code> 控制器中的方法不受存取控制的限制。 <code v-pre>rules</code> 选项列出了 [[yii\filters\AccessRule|存取规则 (access rules)]]，解读如下：</p>
<ul>
<li>允许所有访客（还未经认证的用户）执行 <code v-pre>login</code> 和 <code v-pre>signup</code> 动作。 <code v-pre>roles</code> 选项包含的问号 <code v-pre>?</code> 是一个特殊的标识，代表”访客用户”。</li>
<li>允许已认证用户执行 <code v-pre>logout</code> 动作。<code v-pre>@</code>是另一个特殊标识， 代表”已认证用户”。</li>
</ul>
<p>ACF 自顶向下逐一检查存取规则，直到找到一个与当前 欲执行的动作相符的规则。 然后该匹配规则中的 <code v-pre>allow</code> 选项的值用于判定该用户是否获得授权。如果没有找到匹配的规则， 意味着该用户没有获得授权。（译者注： <code v-pre>only</code> 中没有列出的动作，将无条件获得授权）</p>
<p>当 ACF 判定一个用户没有获得执行当前动作的授权时，它的默认处理是：</p>
<ul>
<li>如果该用户是访客，将调用 [[yii\web\User::loginRequired()]] 将用户的浏览器重定向到登录页面。</li>
<li>如果该用户是已认证用户，将抛出一个 [[yii\web\ForbiddenHttpException]] 异常。</li>
</ul>
<p>你可以通过配置 [[yii\filters\AccessControl::denyCallback]] 属性定制该行为：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token punctuation">[</span></span>
<span class="line">    <span class="token string single-quoted-string">'class'</span> <span class="token operator">=></span> <span class="token class-name static-context">AccessControl</span><span class="token operator">::</span><span class="token keyword">class</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token operator">...</span></span>
<span class="line">    <span class="token string single-quoted-string">'denyCallback'</span> <span class="token operator">=></span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token variable">$rule</span><span class="token punctuation">,</span> <span class="token variable">$action</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">        <span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name class-name-fully-qualified"><span class="token punctuation">\</span>Exception</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'You are not allowed to access this page'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line">    <span class="token punctuation">}</span></span>
<span class="line"><span class="token punctuation">]</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>[[yii\filters\AccessRule|Access rules]] 支持很多的选项。下列是所支持选项的总览。 你可以派生 [[yii\filters\AccessRule]] 来创建自定义的存取规则类。</p>
<ul>
<li>
<p>[[yii\filters\AccessRule::allow|allow]]： 指定该规则是 “允许” 还是 “拒绝” 。（译者注：true是允许，false是拒绝）</p>
</li>
<li>
<p>[[yii\filters\AccessRule::actions|actions]]：指定该规则用于匹配哪些动作。 它的值应该是动作方法的ID数组。匹配比较是大小写敏感的。如果该选项为空，或者不使用该选项， 意味着当前规则适用于所有的动作。</p>
</li>
<li>
<p>[[yii\filters\AccessRule::controllers|controllers]]：指定该规则用于匹配哪些控制器。 它的值应为控制器ID数组。匹配比较是大小写敏感的。如果该选项为空，或者不使用该选项， 则意味着当前规则适用于所有的动作。（译者注：这个选项一般是在控制器的自定义父类中使用才有意义）</p>
</li>
<li>
<p>[[yii\filters\AccessRule::roles|roles]]：指定该规则用于匹配哪些用户角色。 系统自带两个特殊的角色，通过 [[yii\web\User::isGuest]] 来判断：</p>
<ul>
<li><code v-pre>?</code>： 用于匹配访客用户 （未经认证）</li>
<li><code v-pre>@</code>： 用于匹配已认证用户</li>
</ul>
<p>使用其他角色名时，将触发调用 [[yii\web\User::can()]]，这时要求 RBAC 的支持 （在下一节中阐述）。 如果该选项为空或者不使用该选项，意味着该规则适用于所有角色。</p>
</li>
<li>
<p>[[yii\filters\AccessRule::roleParams|roleParams]]：指定将传递给 [[yii\web\User::can()]] 的参数。 请参阅下面描述RBAC规则的部分，了解如何使用它。 如果此选项为空或未设置，则不传递任何参数。</p>
</li>
<li>
<p>[[yii\filters\AccessRule::ips|ips]]：指定该规则用于匹配哪些 [[yii\web\Request::userIP|客户端IP地址]] 。 IP 地址可在其末尾包含通配符 <code v-pre>*</code> 以匹配一批前缀相同的IP地址。 例如，<code v-pre>192.168.*</code> 匹配所有 <code v-pre>192.168.</code> 段的IP地址。 如果该选项为空或者不使用该选项，意味着该规则适用于所有角色。</p>
</li>
<li>
<p>[[yii\filters\AccessRule::verbs|verbs]]：指定该规则用于匹配哪种请求方法（例如<code v-pre>GET</code>，<code v-pre>POST</code>）。 这里的匹配大小写不敏感。</p>
</li>
<li>
<p>[[yii\filters\AccessRule::matchCallback|matchCallback]]：指定一个PHP回调函数用于 判定该规则是否满足条件。（译者注：此处的回调函数是匿名函数）</p>
</li>
<li>
<p>[[yii\filters\AccessRule::denyCallback|denyCallback]]: 指定一个PHP回调函数， 当这个规则不满足条件时该函数会被调用。（译者注：此处的回调函数是匿名函数）</p>
</li>
</ul>
<p>以下例子展示了如何使用 <code v-pre>matchCallback</code> 选项， 可使你设计任意的访问权限检查逻辑：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">yii<span class="token punctuation">\</span>filters<span class="token punctuation">\</span>AccessControl</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">class</span> <span class="token class-name-definition class-name">SiteController</span> <span class="token keyword">extends</span> <span class="token class-name">Controller</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">behaviors</span><span class="token punctuation">(</span><span class="token punctuation">)</span></span>
<span class="line">    <span class="token punctuation">{</span></span>
<span class="line">        <span class="token keyword">return</span> <span class="token punctuation">[</span></span>
<span class="line">            <span class="token string single-quoted-string">'access'</span> <span class="token operator">=></span> <span class="token punctuation">[</span></span>
<span class="line">                <span class="token string single-quoted-string">'class'</span> <span class="token operator">=></span> <span class="token class-name static-context">AccessControl</span><span class="token operator">::</span><span class="token keyword">class</span><span class="token punctuation">,</span></span>
<span class="line">                <span class="token string single-quoted-string">'only'</span> <span class="token operator">=></span> <span class="token punctuation">[</span><span class="token string single-quoted-string">'special-callback'</span><span class="token punctuation">]</span><span class="token punctuation">,</span></span>
<span class="line">                <span class="token string single-quoted-string">'rules'</span> <span class="token operator">=></span> <span class="token punctuation">[</span></span>
<span class="line">                    <span class="token punctuation">[</span></span>
<span class="line">                        <span class="token string single-quoted-string">'actions'</span> <span class="token operator">=></span> <span class="token punctuation">[</span><span class="token string single-quoted-string">'special-callback'</span><span class="token punctuation">]</span><span class="token punctuation">,</span></span>
<span class="line">                        <span class="token string single-quoted-string">'allow'</span> <span class="token operator">=></span> <span class="token constant boolean">true</span><span class="token punctuation">,</span></span>
<span class="line">                        <span class="token string single-quoted-string">'matchCallback'</span> <span class="token operator">=></span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token variable">$rule</span><span class="token punctuation">,</span> <span class="token variable">$action</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">                            <span class="token keyword">return</span> <span class="token function">date</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'d-m'</span><span class="token punctuation">)</span> <span class="token operator">===</span> <span class="token string single-quoted-string">'31-10'</span><span class="token punctuation">;</span></span>
<span class="line">                        <span class="token punctuation">}</span></span>
<span class="line">                    <span class="token punctuation">]</span><span class="token punctuation">,</span></span>
<span class="line">                <span class="token punctuation">]</span><span class="token punctuation">,</span></span>
<span class="line">            <span class="token punctuation">]</span><span class="token punctuation">,</span></span>
<span class="line">        <span class="token punctuation">]</span><span class="token punctuation">;</span></span>
<span class="line">    <span class="token punctuation">}</span></span>
<span class="line"></span>
<span class="line">    <span class="token comment">// 匹配的回调函数被调用了！这个页面只有每年的10月31号能访问（译者注：原文在这里说该方法是回调函数不确切，读者不要和 `matchCallback` 的值即匿名的回调函数混淆理解）。</span></span>
<span class="line">    <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">actionSpecialCallback</span><span class="token punctuation">(</span><span class="token punctuation">)</span></span>
<span class="line">    <span class="token punctuation">{</span></span>
<span class="line">        <span class="token keyword">return</span> <span class="token variable">$this</span><span class="token operator">-></span><span class="token function">render</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'happy-halloween'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line">    <span class="token punctuation">}</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h2 id="基于角色的存取控制-rbac" tabindex="-1"><a class="header-anchor" href="#基于角色的存取控制-rbac"><span>基于角色的存取控制（RBAC）</span></a></h2>
<p>基于角色的存取控制（RBAC）提供了一个简单而强大的集中式存取控制机制。详细的关于 RBAC 和诸多传统的存取控制方案对比的详情，请参阅 <a href="http://en.wikipedia.org/wiki/Role-based_access_control" target="_blank" rel="noopener noreferrer">Wikipedia</a>。</p>
<p>Yii 实现了通用的分层的 RBAC，遵循的模型是 <a href="https://csrc.nist.gov/CSRC/media/Publications/conference-paper/1992/10/13/role-based-access-controls/documents/ferraiolo-kuhn-92.pdf" target="_blank" rel="noopener noreferrer">NIST RBAC model</a>. 它通过 [[yii\rbac\ManagerInterface|authManager]] <a href="https://github.com/yiisoft/yii2/blob/master/docs/guide-zh-CN/structure-application-components.md" target="_blank" rel="noopener noreferrer">application component</a> 提供 RBAC 功能。</p>
<p>使用 RBAC 涉及到两部分工作。第一部分是建立授权数据，而第二部分是使用这些授权数据在需要的地方执行检查。</p>
<p>为方便后面的讲述，这里先介绍一些 RBAC 的基本概念。</p>
<h3 id="基本概念" tabindex="-1"><a class="header-anchor" href="#基本概念"><span>基本概念</span></a></h3>
<p>角色是 <em>权限</em> 的集合（例如：建贴、改贴）。一个角色 可以指派给一个或者多个用户。要检查某用户是否有一个特定的权限， 系统会检查该包含该权限的角色是否指派给了该用户。</p>
<p>可以用一个规则 <em>rule</em> 与一个角色或者权限关联。一个规则用一段代码代表， 规则的执行是在检查一个用户是否满足这个角色或者权限时进行的。例如，”改帖” 的权限 可以使用一个检查该用户是否是帖子的创建者的规则。权限检查中，如果该用户 不是帖子创建者，那么他（她）将被认为不具有 “改帖”的权限。</p>
<p>角色和权限都可以按层次组织。特定情况下，一个角色可能由其他角色或权限构成， 而权限又由其他的权限构成。Yii 实现了所谓的 <em>局部顺序</em> 的层次结构，包含更多的特定的 <em>树</em> 的层次。 一个角色可以包含一个权限，反之则不行。（译者注：可理解为角色在上方，权限在下方，从上到下如果碰到权限那么再往下不能出现角色）</p>
<h3 id="配置-rbac" tabindex="-1"><a class="header-anchor" href="#配置-rbac"><span>配置 RBAC</span></a></h3>
<p>在开始定义授权数据和执行存取检查之前，需要先配置应用组件 [[yii\base\Application::authManager|authManager]] 。 Yii 提供了两套授权管理器： [[yii\rbac\PhpManager]] 和 [[yii\rbac\DbManager]]。前者使用 PHP 脚本存放授权数据， 而后者使用数据库存放授权数据。 如果你的应用不要求大量的动态角色和权限管理， 你可以考虑使用前者。</p>
<h4 id="使用-phpmanager" tabindex="-1"><a class="header-anchor" href="#使用-phpmanager"><span>使用 <code v-pre>PhpManager</code></span></a></h4>
<p>以下代码展示使用 [[yii\rbac\PhpManager]] 时如何在应用配置文件中配置 <code v-pre>authManager</code>：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">return</span> <span class="token punctuation">[</span></span>
<span class="line">    <span class="token comment">// ...</span></span>
<span class="line">    <span class="token string single-quoted-string">'components'</span> <span class="token operator">=></span> <span class="token punctuation">[</span></span>
<span class="line">        <span class="token string single-quoted-string">'authManager'</span> <span class="token operator">=></span> <span class="token punctuation">[</span></span>
<span class="line">            <span class="token string single-quoted-string">'class'</span> <span class="token operator">=></span> <span class="token string single-quoted-string">'yii\rbac\PhpManager'</span><span class="token punctuation">,</span></span>
<span class="line">        <span class="token punctuation">]</span><span class="token punctuation">,</span></span>
<span class="line">        <span class="token comment">// ...</span></span>
<span class="line">    <span class="token punctuation">]</span><span class="token punctuation">,</span></span>
<span class="line"><span class="token punctuation">]</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>现在可以通过 <code v-pre>\Yii::$app-&gt;authManager</code> 访问 <code v-pre>authManager</code> 。</p>
<p>[[yii\rbac\PhpManager]] 默认将 RBAC 数据保存在 <code v-pre>@app/rbac</code> 目录下的文件中。 如果权限层次数据在运行时会被修改，需确保WEB服务器进程对该目录和其中的文件有写权限。</p>
<h4 id="使用-dbmanager" tabindex="-1"><a class="header-anchor" href="#使用-dbmanager"><span>使用 <code v-pre>DbManager</code></span></a></h4>
<p>以下代码展示使用 [[yii\rbac\DbManager]] 时如何在应用配置文件中配置 <code v-pre>authManager</code>：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">return</span> <span class="token punctuation">[</span></span>
<span class="line">    <span class="token comment">// ...</span></span>
<span class="line">    <span class="token string single-quoted-string">'components'</span> <span class="token operator">=></span> <span class="token punctuation">[</span></span>
<span class="line">        <span class="token string single-quoted-string">'authManager'</span> <span class="token operator">=></span> <span class="token punctuation">[</span></span>
<span class="line">            <span class="token string single-quoted-string">'class'</span> <span class="token operator">=></span> <span class="token string single-quoted-string">'yii\rbac\DbManager'</span><span class="token punctuation">,</span></span>
<span class="line">            <span class="token comment">// uncomment if you want to cache RBAC items hierarchy</span></span>
<span class="line">            <span class="token comment">// 'cache' => 'cache',</span></span>
<span class="line">        <span class="token punctuation">]</span><span class="token punctuation">,</span></span>
<span class="line">        <span class="token comment">// ...</span></span>
<span class="line">    <span class="token punctuation">]</span><span class="token punctuation">,</span></span>
<span class="line"><span class="token punctuation">]</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><blockquote>
<p>Note: 如果您使用的是 yii2-basic-app 模板，则有一个 <code v-pre>config/console.php</code> 配置文件，其中 <code v-pre>authManager</code> 需要另外声明在 <code v-pre>config/web.php</code>。 在 yii2-advanced-app 的情况下，<code v-pre>authManager</code> 只能在 <code v-pre>common/config/main.php</code> 中声明一次。</p>
</blockquote>
<p><code v-pre>DbManager</code> 使用4个数据库表存放它的数据：</p>
<ul>
<li>[[yii\rbac\DbManager::$itemTable|itemTable]]： 该表存放授权条目（译者注：即角色和权限）。默认表名为 “auth_item” 。</li>
<li>[[yii\rbac\DbManager::$itemChildTable|itemChildTable]]： 该表存放授权条目的层次关系。默认表名为 “auth_item_child”。</li>
<li>[[yii\rbac\DbManager::$assignmentTable|assignmentTable]]： 该表存放授权条目对用户的指派情况。默认表名为 “auth_assignment”。</li>
<li>[[yii\rbac\DbManager::$ruleTable|ruleTable]]： 该表存放规则。默认表名为 “auth_rule”。</li>
</ul>
<p>继续之前，你需要在数据库中创建这些表。你可以使用存放在 <code v-pre>@yii/rbac/migrations</code> 目录中的数据库迁移文件来做这件事（译者注：根据本人经验，最好是将授权数据初始化命令也写到这个 RBAC 数据库迁移文件中）：</p>
<p><code v-pre>yii migrate --migrationPath=@yii/rbac/migrations</code></p>
<p>阅读 <a href="https://github.com/yiisoft/yii2/blob/master/docs/guide-zh-CN/db-migrations.md#separated-migrations" target="_blank" rel="noopener noreferrer">Separated Migrations</a> 部分中有关处理来自不同名称空间的迁移的更多信息。</p>
<p>现在可以通过 <code v-pre>\Yii::$app-&gt;authManager</code> 访问 <code v-pre>authManager</code> 。</p>
<h3 id="建立授权数据" tabindex="-1"><a class="header-anchor" href="#建立授权数据"><span>建立授权数据</span></a></h3>
<p>所有授权数据相关的任务如下：</p>
<ul>
<li>定义角色和权限；</li>
<li>建立角色和权限的关系；</li>
<li>定义规则；</li>
<li>将规则与角色和权限作关联；</li>
<li>指派角色给用户。</li>
</ul>
<p>根据授权灵活性要求，上述任务可以通过不同的方式完成。 如果您的权限层次结构仅由开发人员更改，则可以使用迁移或控制台命令。 Migration pro 是可以与其他迁移一起执行的。 控制台命令 pro 是您可以很好地了解代码中的层次结构， 而不是分散在多个迁移中。</p>
<p>无论哪种方式，最终都会得到以下 RBAC 层次结构：</p>
<p><img src="https://cdn.learnku.com/uploads/images/202202/25/93088/p6kVIUnxrN.png!large" alt="简单的 RBAC 层次结构"></p>
<p>如果您需要动态形成权限层次结构，则需要 UI 或控制台命令。 用于构建层次结构的 API 本身不会有所不同。</p>
<h4 id="使用迁移-using-migrations" tabindex="-1"><a class="header-anchor" href="#使用迁移-using-migrations"><span>使用迁移（Using migrations）</span></a></h4>
<p>您可以使用 <a href="https://github.com/yiisoft/yii2/blob/master/docs/guide-zh-CN/db-migrations.md" target="_blank" rel="noopener noreferrer">migrations</a> 通过 <code v-pre>authManager</code> 提供的 API 初始化和修改层次结构。</p>
<p>使用 <code v-pre>./yii migrate/create init_rbac</code> 创建新迁移，然后实现创建层次结构：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token php language-php"><span class="token delimiter important">&lt;?php</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">yii<span class="token punctuation">\</span>db<span class="token punctuation">\</span>Migration</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">class</span> <span class="token class-name-definition class-name">m170124_084304_init_rbac</span> <span class="token keyword">extends</span> <span class="token class-name">Migration</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">up</span><span class="token punctuation">(</span><span class="token punctuation">)</span></span>
<span class="line">    <span class="token punctuation">{</span></span>
<span class="line">        <span class="token variable">$auth</span> <span class="token operator">=</span> <span class="token class-name static-context">Yii</span><span class="token operator">::</span><span class="token variable">$app</span><span class="token operator">-></span><span class="token property">authManager</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line">        <span class="token comment">// 添加 "createPost" 权限</span></span>
<span class="line">        <span class="token variable">$createPost</span> <span class="token operator">=</span> <span class="token variable">$auth</span><span class="token operator">-></span><span class="token function">createPermission</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'createPost'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line">        <span class="token variable">$createPost</span><span class="token operator">-></span><span class="token property">description</span> <span class="token operator">=</span> <span class="token string single-quoted-string">'Create a post'</span><span class="token punctuation">;</span></span>
<span class="line">        <span class="token variable">$auth</span><span class="token operator">-></span><span class="token function">add</span><span class="token punctuation">(</span><span class="token variable">$createPost</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line">        <span class="token comment">// 添加 "updatePost" 权限</span></span>
<span class="line">        <span class="token variable">$updatePost</span> <span class="token operator">=</span> <span class="token variable">$auth</span><span class="token operator">-></span><span class="token function">createPermission</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'updatePost'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line">        <span class="token variable">$updatePost</span><span class="token operator">-></span><span class="token property">description</span> <span class="token operator">=</span> <span class="token string single-quoted-string">'Update post'</span><span class="token punctuation">;</span></span>
<span class="line">        <span class="token variable">$auth</span><span class="token operator">-></span><span class="token function">add</span><span class="token punctuation">(</span><span class="token variable">$updatePost</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line">        <span class="token comment">// 添加 "author" 角色并赋予 "createPost" 权限</span></span>
<span class="line">        <span class="token variable">$author</span> <span class="token operator">=</span> <span class="token variable">$auth</span><span class="token operator">-></span><span class="token function">createRole</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'author'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line">        <span class="token variable">$auth</span><span class="token operator">-></span><span class="token function">add</span><span class="token punctuation">(</span><span class="token variable">$author</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line">        <span class="token variable">$auth</span><span class="token operator">-></span><span class="token function">addChild</span><span class="token punctuation">(</span><span class="token variable">$author</span><span class="token punctuation">,</span> <span class="token variable">$createPost</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line">        <span class="token comment">// 添加 "admin" 角色并赋予 "updatePost" </span></span>
<span class="line">        <span class="token comment">// 和 "author" 权限</span></span>
<span class="line">        <span class="token variable">$admin</span> <span class="token operator">=</span> <span class="token variable">$auth</span><span class="token operator">-></span><span class="token function">createRole</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'admin'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line">        <span class="token variable">$auth</span><span class="token operator">-></span><span class="token function">add</span><span class="token punctuation">(</span><span class="token variable">$admin</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line">        <span class="token variable">$auth</span><span class="token operator">-></span><span class="token function">addChild</span><span class="token punctuation">(</span><span class="token variable">$admin</span><span class="token punctuation">,</span> <span class="token variable">$updatePost</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line">        <span class="token variable">$auth</span><span class="token operator">-></span><span class="token function">addChild</span><span class="token punctuation">(</span><span class="token variable">$admin</span><span class="token punctuation">,</span> <span class="token variable">$author</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line">        <span class="token comment">// 为用户指派角色。其中 1 和 2 是由 IdentityInterface::getId() 返回的id</span></span>
<span class="line">        <span class="token comment">// 通常在你的 User 模型中实现这个函数。</span></span>
<span class="line">        <span class="token variable">$auth</span><span class="token operator">-></span><span class="token function">assign</span><span class="token punctuation">(</span><span class="token variable">$author</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line">        <span class="token variable">$auth</span><span class="token operator">-></span><span class="token function">assign</span><span class="token punctuation">(</span><span class="token variable">$admin</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line">    <span class="token punctuation">}</span></span>
<span class="line"></span>
<span class="line">    <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">down</span><span class="token punctuation">(</span><span class="token punctuation">)</span></span>
<span class="line">    <span class="token punctuation">{</span></span>
<span class="line">        <span class="token variable">$auth</span> <span class="token operator">=</span> <span class="token class-name static-context">Yii</span><span class="token operator">::</span><span class="token variable">$app</span><span class="token operator">-></span><span class="token property">authManager</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line">        <span class="token variable">$auth</span><span class="token operator">-></span><span class="token function">removeAll</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line">    <span class="token punctuation">}</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><blockquote>
<p>如果您不想硬编码哪些用户具有某些角色，请不要在迁移中使用 <code v-pre>-&gt;assign()</code> 调用。 相反，请创建UI或控制台命令来管理分配。</p>
</blockquote>
<p>迁移可以通过 <code v-pre>yii migrate</code> 使用。</p>
<h3 id="使用控制台命令-using-console-command" tabindex="-1"><a class="header-anchor" href="#使用控制台命令-using-console-command"><span>使用控制台命令（Using console command）</span></a></h3>
<p>如果您的权限层次根本没有改变，并且您拥有固定数量的用户， 则可以创建一个<a href="https://github.com/yiisoft/yii2/blob/master/docs/guide-zh-CN/tutorial-console.md#create-command" target="_blank" rel="noopener noreferrer">控制台命令</a>，它将通过 <code v-pre>authManager</code> 提供的 API 初始化授权数据一次：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token php language-php"><span class="token delimiter important">&lt;?php</span></span>
<span class="line"><span class="token keyword">namespace</span> <span class="token package">app<span class="token punctuation">\</span>commands</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Yii</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">yii<span class="token punctuation">\</span>console<span class="token punctuation">\</span>Controller</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">class</span> <span class="token class-name-definition class-name">RbacController</span> <span class="token keyword">extends</span> <span class="token class-name">Controller</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">actionInit</span><span class="token punctuation">(</span><span class="token punctuation">)</span></span>
<span class="line">    <span class="token punctuation">{</span></span>
<span class="line">        <span class="token variable">$auth</span> <span class="token operator">=</span> <span class="token class-name static-context">Yii</span><span class="token operator">::</span><span class="token variable">$app</span><span class="token operator">-></span><span class="token property">authManager</span><span class="token punctuation">;</span></span>
<span class="line">        <span class="token variable">$auth</span><span class="token operator">-></span><span class="token function">removeAll</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line">        <span class="token comment">// 添加 "createPost" 权限</span></span>
<span class="line">        <span class="token variable">$createPost</span> <span class="token operator">=</span> <span class="token variable">$auth</span><span class="token operator">-></span><span class="token function">createPermission</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'createPost'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line">        <span class="token variable">$createPost</span><span class="token operator">-></span><span class="token property">description</span> <span class="token operator">=</span> <span class="token string single-quoted-string">'Create a post'</span><span class="token punctuation">;</span></span>
<span class="line">        <span class="token variable">$auth</span><span class="token operator">-></span><span class="token function">add</span><span class="token punctuation">(</span><span class="token variable">$createPost</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line">        <span class="token comment">// 添加 "updatePost" 权限</span></span>
<span class="line">        <span class="token variable">$updatePost</span> <span class="token operator">=</span> <span class="token variable">$auth</span><span class="token operator">-></span><span class="token function">createPermission</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'updatePost'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line">        <span class="token variable">$updatePost</span><span class="token operator">-></span><span class="token property">description</span> <span class="token operator">=</span> <span class="token string single-quoted-string">'Update post'</span><span class="token punctuation">;</span></span>
<span class="line">        <span class="token variable">$auth</span><span class="token operator">-></span><span class="token function">add</span><span class="token punctuation">(</span><span class="token variable">$updatePost</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line">        <span class="token comment">// 添加 "author" 角色并赋予 "createPost" 权限</span></span>
<span class="line">        <span class="token variable">$author</span> <span class="token operator">=</span> <span class="token variable">$auth</span><span class="token operator">-></span><span class="token function">createRole</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'author'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line">        <span class="token variable">$auth</span><span class="token operator">-></span><span class="token function">add</span><span class="token punctuation">(</span><span class="token variable">$author</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line">        <span class="token variable">$auth</span><span class="token operator">-></span><span class="token function">addChild</span><span class="token punctuation">(</span><span class="token variable">$author</span><span class="token punctuation">,</span> <span class="token variable">$createPost</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line">        <span class="token comment">// 添加 "admin" 角色并赋予 "updatePost" </span></span>
<span class="line">        <span class="token comment">// 和 "author" 权限</span></span>
<span class="line">        <span class="token variable">$admin</span> <span class="token operator">=</span> <span class="token variable">$auth</span><span class="token operator">-></span><span class="token function">createRole</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'admin'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line">        <span class="token variable">$auth</span><span class="token operator">-></span><span class="token function">add</span><span class="token punctuation">(</span><span class="token variable">$admin</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line">        <span class="token variable">$auth</span><span class="token operator">-></span><span class="token function">addChild</span><span class="token punctuation">(</span><span class="token variable">$admin</span><span class="token punctuation">,</span> <span class="token variable">$updatePost</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line">        <span class="token variable">$auth</span><span class="token operator">-></span><span class="token function">addChild</span><span class="token punctuation">(</span><span class="token variable">$admin</span><span class="token punctuation">,</span> <span class="token variable">$author</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line">        <span class="token comment">// 为用户指派角色。其中 1 和 2 是由 IdentityInterface::getId() 返回的id</span></span>
<span class="line">        <span class="token comment">// 通常在你的 User 模型中实现这个函数。</span></span>
<span class="line">        <span class="token variable">$auth</span><span class="token operator">-></span><span class="token function">assign</span><span class="token punctuation">(</span><span class="token variable">$author</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line">        <span class="token variable">$auth</span><span class="token operator">-></span><span class="token function">assign</span><span class="token punctuation">(</span><span class="token variable">$admin</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line">    <span class="token punctuation">}</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><blockquote>
<p>Note: 如果您使用高级模板，则需要将 <code v-pre>RbacController</code> 放在 <code v-pre>console/controllers</code> 目录中， 并将命名空间更改为 <code v-pre>console/controllers</code>。</p>
</blockquote>
<p>上面的命令可以通过以下方式从控制台执行：</p>
<div class="language-bash line-numbers-mode" data-highlighter="prismjs" data-ext="sh" data-title="sh"><pre v-pre class="language-bash"><code><span class="line">php yii rbac/init</span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><blockquote>
<p>如果您不想硬编码用户具有某些角色，请不要将 <code v-pre>-&gt;assign()</code> 调用放入命令中。 相反，请创建UI或控制台命令来管理分配。</p>
</blockquote>
<h2 id="为用户分配角色-assigning-roles-to-users" tabindex="-1"><a class="header-anchor" href="#为用户分配角色-assigning-roles-to-users"><span>为用户分配角色（Assigning roles to users）</span></a></h2>
<p>作者可以创建帖子，管理员可以更新帖子并可以做一切作者都能做的。</p>
<p>如果您的应用程序允许用户注册，则需要为这些新用户分配一次角色。 例如，为了让所有注册用户成为高级项目模板中的作者，您需要修改 <code v-pre>frontend\models\SignupForm::signup()</code>， 如下所示：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">signup</span><span class="token punctuation">(</span><span class="token punctuation">)</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token variable">$this</span><span class="token operator">-></span><span class="token function">validate</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">        <span class="token variable">$user</span> <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">User</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line">        <span class="token variable">$user</span><span class="token operator">-></span><span class="token property">username</span> <span class="token operator">=</span> <span class="token variable">$this</span><span class="token operator">-></span><span class="token property">username</span><span class="token punctuation">;</span></span>
<span class="line">        <span class="token variable">$user</span><span class="token operator">-></span><span class="token property">email</span> <span class="token operator">=</span> <span class="token variable">$this</span><span class="token operator">-></span><span class="token property">email</span><span class="token punctuation">;</span></span>
<span class="line">        <span class="token variable">$user</span><span class="token operator">-></span><span class="token function">setPassword</span><span class="token punctuation">(</span><span class="token variable">$this</span><span class="token operator">-></span><span class="token property">password</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line">        <span class="token variable">$user</span><span class="token operator">-></span><span class="token function">generateAuthKey</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line">        <span class="token variable">$user</span><span class="token operator">-></span><span class="token function">save</span><span class="token punctuation">(</span><span class="token constant boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line">        <span class="token comment">// 增加了以下三行：</span></span>
<span class="line">        <span class="token variable">$auth</span> <span class="token operator">=</span> <span class="token class-name class-name-fully-qualified static-context"><span class="token punctuation">\</span>Yii</span><span class="token operator">::</span><span class="token variable">$app</span><span class="token operator">-></span><span class="token property">authManager</span><span class="token punctuation">;</span></span>
<span class="line">        <span class="token variable">$authorRole</span> <span class="token operator">=</span> <span class="token variable">$auth</span><span class="token operator">-></span><span class="token function">getRole</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'author'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line">        <span class="token variable">$auth</span><span class="token operator">-></span><span class="token function">assign</span><span class="token punctuation">(</span><span class="token variable">$authorRole</span><span class="token punctuation">,</span> <span class="token variable">$user</span><span class="token operator">-></span><span class="token function">getId</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line">        <span class="token keyword">return</span> <span class="token variable">$user</span><span class="token punctuation">;</span></span>
<span class="line">    <span class="token punctuation">}</span></span>
<span class="line"></span>
<span class="line">    <span class="token keyword">return</span> <span class="token constant">null</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>对于需要动态更新授权数据的复杂访问控制的应用程序，可能需要使用 <code v-pre>authManager</code> 提供的 API 来开发特殊的用户界面（即管理面板）。</p>
<h3 id="使用规则-rules" tabindex="-1"><a class="header-anchor" href="#使用规则-rules"><span>使用规则 (Rules)</span></a></h3>
<p>如前所述，规则给角色和权限增加额外的约束条件。规则是 [[yii\rbac\Rule]] 的派生类。 它需要实现 [[yii\rbac\Rule::execute()|execute()]] 方法。在之前我们创建的层次结构中，作者不能编辑自己的帖子，我们来修正这个问题。 首先我们需要一个规则来认证当前用户是帖子的作者：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">namespace</span> <span class="token package">app<span class="token punctuation">\</span>rbac</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">yii<span class="token punctuation">\</span>rbac<span class="token punctuation">\</span>Rule</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">app<span class="token punctuation">\</span>models<span class="token punctuation">\</span>Post</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token doc-comment comment">/**</span>
<span class="line"> * 检查 authorID 是否和通过参数传进来的 user 参数相符</span>
<span class="line"> */</span></span>
<span class="line"><span class="token keyword">class</span> <span class="token class-name-definition class-name">AuthorRule</span> <span class="token keyword">extends</span> <span class="token class-name">Rule</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token keyword">public</span> <span class="token variable">$name</span> <span class="token operator">=</span> <span class="token string single-quoted-string">'isAuthor'</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line">    <span class="token doc-comment comment">/**</span>
<span class="line">     * <span class="token keyword">@param</span> <span class="token class-name"><span class="token keyword">string</span><span class="token punctuation">|</span><span class="token keyword">integer</span></span> <span class="token parameter">$user</span> 用户 ID.</span>
<span class="line">     * <span class="token keyword">@param</span> <span class="token class-name">Item</span> <span class="token parameter">$item</span> 该规则相关的角色或者权限</span>
<span class="line">     * <span class="token keyword">@param</span> <span class="token class-name"><span class="token keyword">array</span></span> <span class="token parameter">$params</span> 传给 ManagerInterface::checkAccess() 的参数</span>
<span class="line">     * <span class="token keyword">@return</span> <span class="token class-name"><span class="token keyword">boolean</span></span> 代表该规则相关的角色或者权限是否被允许</span>
<span class="line">     */</span></span>
<span class="line">    <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">execute</span><span class="token punctuation">(</span><span class="token variable">$user</span><span class="token punctuation">,</span> <span class="token variable">$item</span><span class="token punctuation">,</span> <span class="token variable">$params</span><span class="token punctuation">)</span></span>
<span class="line">    <span class="token punctuation">{</span></span>
<span class="line">        <span class="token keyword">return</span> <span class="token keyword">isset</span><span class="token punctuation">(</span><span class="token variable">$params</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'post'</span><span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token operator">?</span> <span class="token variable">$params</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'post'</span><span class="token punctuation">]</span><span class="token operator">-></span><span class="token property">createdBy</span> <span class="token operator">==</span> <span class="token variable">$user</span> <span class="token punctuation">:</span> <span class="token constant boolean">false</span><span class="token punctuation">;</span></span>
<span class="line">    <span class="token punctuation">}</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>上述规则检查 <code v-pre>post</code> 是否是 <code v-pre>$user</code> 创建的。我们还要在之前的命令中 创建一个特别的权限 <code v-pre>updateOwnPost</code> ：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$auth</span> <span class="token operator">=</span> <span class="token class-name static-context">Yii</span><span class="token operator">::</span><span class="token variable">$app</span><span class="token operator">-></span><span class="token property">authManager</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token comment">// 添加规则</span></span>
<span class="line"><span class="token variable">$rule</span> <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name class-name-fully-qualified"><span class="token punctuation">\</span>app<span class="token punctuation">\</span>rbac<span class="token punctuation">\</span>AuthorRule</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token variable">$auth</span><span class="token operator">-></span><span class="token function">add</span><span class="token punctuation">(</span><span class="token variable">$rule</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token comment">// 添加 "updateOwnPost" 权限并与规则关联</span></span>
<span class="line"><span class="token variable">$updateOwnPost</span> <span class="token operator">=</span> <span class="token variable">$auth</span><span class="token operator">-></span><span class="token function">createPermission</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'updateOwnPost'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token variable">$updateOwnPost</span><span class="token operator">-></span><span class="token property">description</span> <span class="token operator">=</span> <span class="token string single-quoted-string">'Update own post'</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token variable">$updateOwnPost</span><span class="token operator">-></span><span class="token property">ruleName</span> <span class="token operator">=</span> <span class="token variable">$rule</span><span class="token operator">-></span><span class="token property">name</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token variable">$auth</span><span class="token operator">-></span><span class="token function">add</span><span class="token punctuation">(</span><span class="token variable">$updateOwnPost</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token comment">// "updateOwnPost" 权限将由 "updatePost" 权限使用</span></span>
<span class="line"><span class="token variable">$auth</span><span class="token operator">-></span><span class="token function">addChild</span><span class="token punctuation">(</span><span class="token variable">$updateOwnPost</span><span class="token punctuation">,</span> <span class="token variable">$updatePost</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token comment">// 允许 "author" 更新自己的帖子</span></span>
<span class="line"><span class="token variable">$auth</span><span class="token operator">-></span><span class="token function">addChild</span><span class="token punctuation">(</span><span class="token variable">$author</span><span class="token punctuation">,</span> <span class="token variable">$updateOwnPost</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>现在我们得到如下层次结构:</p>
<p><img src="https://cdn.learnku.com/uploads/images/202202/25/93088/KleCe52YAj.png!large" alt="带有规则的 RBAC 层次结构"></p>
<h3 id="存取检查" tabindex="-1"><a class="header-anchor" href="#存取检查"><span>存取检查</span></a></h3>
<p>授权数据准备好后，存取检查简单到只需要一个方法调用 [[yii\rbac\ManagerInterface::checkAccess()]]。 因为大多数存取检查都是针对当前用户而言，为方便起见， Yii 提供了一个快捷方法 [[yii\web\User::can()]]，可以如下例所示来使用：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token class-name class-name-fully-qualified static-context"><span class="token punctuation">\</span>Yii</span><span class="token operator">::</span><span class="token variable">$app</span><span class="token operator">-></span><span class="token property">user</span><span class="token operator">-></span><span class="token function">can</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'createPost'</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token comment">// 建贴</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>如果当前用户是 <code v-pre>ID=1</code> 的 Jane ，我们从图中的 <code v-pre>createPost</code> 开始，并试图到达 <code v-pre>Jane</code> 。 （译者注：参照图中红色路线所示的建贴授权流程）</p>
<p><img src="https://cdn.learnku.com/uploads/images/202202/25/93088/XXFAL2s6rl.png!large" alt="存取检验"></p>
<p>为了检查某用户是否能更新帖子，我们需要传递一个额外的参数，该参数是 <code v-pre>AuthorRule</code> 要用的：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token class-name class-name-fully-qualified static-context"><span class="token punctuation">\</span>Yii</span><span class="token operator">::</span><span class="token variable">$app</span><span class="token operator">-></span><span class="token property">user</span><span class="token operator">-></span><span class="token function">can</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'updatePost'</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token string single-quoted-string">'post'</span> <span class="token operator">=></span> <span class="token variable">$post</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token comment">// 更新帖子</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>下图所示为当前用户是 John 时所发生的事情：</p>
<p><img src="https://cdn.learnku.com/uploads/images/202202/25/93088/Mfq6ONLOME.png!large" alt="存取检验"></p>
<p>我们从图中的 <code v-pre>updatePost</code> 开始，经过 <code v-pre>updateOwnPost</code>。为通过检查，<code v-pre>Authorrule</code> 规则的 <code v-pre>execute()</code> 方法应当返回 <code v-pre>true</code> 。该方法从 <code v-pre>can()</code> 方法调用接收到 <code v-pre>$params</code> 参数， 因此它的值是 <code v-pre>['post' =&gt; $post]</code> 。如果一切顺利，我们会达到指派给 John 的 <code v-pre>author</code> 角色。</p>
<p>对于 Jane 来说则更简单，因为她是管理员：</p>
<p><img src="https://cdn.learnku.com/uploads/images/202202/25/93088/OVUMTZrV9F.png!large" alt="存取检验"></p>
<p>在您的控制器内部有几种实现授权的方式。 如果您希望细化权限来分开添加和删除的访问权限，那么您需要检查每个操作的访问权限。 您可以在每个操作方法中使用上述条件，或使用 [[yii\filters\AccessControl]]：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">behaviors</span><span class="token punctuation">(</span><span class="token punctuation">)</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token keyword">return</span> <span class="token punctuation">[</span></span>
<span class="line">        <span class="token string single-quoted-string">'access'</span> <span class="token operator">=></span> <span class="token punctuation">[</span></span>
<span class="line">            <span class="token string single-quoted-string">'class'</span> <span class="token operator">=></span> <span class="token class-name static-context">AccessControl</span><span class="token operator">::</span><span class="token keyword">class</span><span class="token punctuation">,</span></span>
<span class="line">            <span class="token string single-quoted-string">'rules'</span> <span class="token operator">=></span> <span class="token punctuation">[</span></span>
<span class="line">                <span class="token punctuation">[</span></span>
<span class="line">                    <span class="token string single-quoted-string">'allow'</span> <span class="token operator">=></span> <span class="token constant boolean">true</span><span class="token punctuation">,</span></span>
<span class="line">                    <span class="token string single-quoted-string">'actions'</span> <span class="token operator">=></span> <span class="token punctuation">[</span><span class="token string single-quoted-string">'index'</span><span class="token punctuation">]</span><span class="token punctuation">,</span></span>
<span class="line">                    <span class="token string single-quoted-string">'roles'</span> <span class="token operator">=></span> <span class="token punctuation">[</span><span class="token string single-quoted-string">'managePost'</span><span class="token punctuation">]</span><span class="token punctuation">,</span></span>
<span class="line">                <span class="token punctuation">]</span><span class="token punctuation">,</span></span>
<span class="line">                <span class="token punctuation">[</span></span>
<span class="line">                    <span class="token string single-quoted-string">'allow'</span> <span class="token operator">=></span> <span class="token constant boolean">true</span><span class="token punctuation">,</span></span>
<span class="line">                    <span class="token string single-quoted-string">'actions'</span> <span class="token operator">=></span> <span class="token punctuation">[</span><span class="token string single-quoted-string">'view'</span><span class="token punctuation">]</span><span class="token punctuation">,</span></span>
<span class="line">                    <span class="token string single-quoted-string">'roles'</span> <span class="token operator">=></span> <span class="token punctuation">[</span><span class="token string single-quoted-string">'viewPost'</span><span class="token punctuation">]</span><span class="token punctuation">,</span></span>
<span class="line">                <span class="token punctuation">]</span><span class="token punctuation">,</span></span>
<span class="line">                <span class="token punctuation">[</span></span>
<span class="line">                    <span class="token string single-quoted-string">'allow'</span> <span class="token operator">=></span> <span class="token constant boolean">true</span><span class="token punctuation">,</span></span>
<span class="line">                    <span class="token string single-quoted-string">'actions'</span> <span class="token operator">=></span> <span class="token punctuation">[</span><span class="token string single-quoted-string">'create'</span><span class="token punctuation">]</span><span class="token punctuation">,</span></span>
<span class="line">                    <span class="token string single-quoted-string">'roles'</span> <span class="token operator">=></span> <span class="token punctuation">[</span><span class="token string single-quoted-string">'createPost'</span><span class="token punctuation">]</span><span class="token punctuation">,</span></span>
<span class="line">                <span class="token punctuation">]</span><span class="token punctuation">,</span></span>
<span class="line">                <span class="token punctuation">[</span></span>
<span class="line">                    <span class="token string single-quoted-string">'allow'</span> <span class="token operator">=></span> <span class="token constant boolean">true</span><span class="token punctuation">,</span></span>
<span class="line">                    <span class="token string single-quoted-string">'actions'</span> <span class="token operator">=></span> <span class="token punctuation">[</span><span class="token string single-quoted-string">'update'</span><span class="token punctuation">]</span><span class="token punctuation">,</span></span>
<span class="line">                    <span class="token string single-quoted-string">'roles'</span> <span class="token operator">=></span> <span class="token punctuation">[</span><span class="token string single-quoted-string">'updatePost'</span><span class="token punctuation">]</span><span class="token punctuation">,</span></span>
<span class="line">                <span class="token punctuation">]</span><span class="token punctuation">,</span></span>
<span class="line">                <span class="token punctuation">[</span></span>
<span class="line">                    <span class="token string single-quoted-string">'allow'</span> <span class="token operator">=></span> <span class="token constant boolean">true</span><span class="token punctuation">,</span></span>
<span class="line">                    <span class="token string single-quoted-string">'actions'</span> <span class="token operator">=></span> <span class="token punctuation">[</span><span class="token string single-quoted-string">'delete'</span><span class="token punctuation">]</span><span class="token punctuation">,</span></span>
<span class="line">                    <span class="token string single-quoted-string">'roles'</span> <span class="token operator">=></span> <span class="token punctuation">[</span><span class="token string single-quoted-string">'deletePost'</span><span class="token punctuation">]</span><span class="token punctuation">,</span></span>
<span class="line">                <span class="token punctuation">]</span><span class="token punctuation">,</span></span>
<span class="line">            <span class="token punctuation">]</span><span class="token punctuation">,</span></span>
<span class="line">        <span class="token punctuation">]</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token punctuation">]</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>如果所有的CRUD操作都是一起管理的，那么使用 <code v-pre>managePost</code> 这样的单一权限并且在 [[yii\web\Controller::beforeAction()]] 中检查它是个好主意。</p>
<p>在上面的例子中，没有参数与指定的访问动作的角色一起传递，但是在 <code v-pre>updatePost</code> 权限的情况下，我们需要传递 <code v-pre>post</code> 参数才能正常工作。 您可以通过在访问规则中指定 [[yii\filters\AccessRule::roleParams|roleParams]] 将参数传递给 [[yii\web\User::can()]]：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token punctuation">[</span></span>
<span class="line">    <span class="token string single-quoted-string">'allow'</span> <span class="token operator">=></span> <span class="token constant boolean">true</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token string single-quoted-string">'actions'</span> <span class="token operator">=></span> <span class="token punctuation">[</span><span class="token string single-quoted-string">'update'</span><span class="token punctuation">]</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token string single-quoted-string">'roles'</span> <span class="token operator">=></span> <span class="token punctuation">[</span><span class="token string single-quoted-string">'updatePost'</span><span class="token punctuation">]</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token string single-quoted-string">'roleParams'</span> <span class="token operator">=></span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">        <span class="token keyword">return</span> <span class="token punctuation">[</span><span class="token string single-quoted-string">'post'</span> <span class="token operator">=></span> <span class="token class-name static-context">Post</span><span class="token operator">::</span><span class="token function">findOne</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'id'</span> <span class="token operator">=></span> <span class="token class-name static-context">Yii</span><span class="token operator">::</span><span class="token variable">$app</span><span class="token operator">-></span><span class="token property">request</span><span class="token operator">-></span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'id'</span><span class="token punctuation">)</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">]</span><span class="token punctuation">;</span></span>
<span class="line">    <span class="token punctuation">}</span><span class="token punctuation">,</span></span>
<span class="line"><span class="token punctuation">]</span><span class="token punctuation">,</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>在上面的例子中，[[yii\filters\AccessRule::roleParams|roleParams]] 是一个 Closure， 将在检查访问规则时进行评估，因此模型只会在需要时加载。 如果创建角色参数是一个简单的操作，那么您可以指定一个数组，如下所示：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token punctuation">[</span></span>
<span class="line">    <span class="token string single-quoted-string">'allow'</span> <span class="token operator">=></span> <span class="token constant boolean">true</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token string single-quoted-string">'actions'</span> <span class="token operator">=></span> <span class="token punctuation">[</span><span class="token string single-quoted-string">'update'</span><span class="token punctuation">]</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token string single-quoted-string">'roles'</span> <span class="token operator">=></span> <span class="token punctuation">[</span><span class="token string single-quoted-string">'updatePost'</span><span class="token punctuation">]</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token string single-quoted-string">'roleParams'</span> <span class="token operator">=></span> <span class="token punctuation">[</span><span class="token string single-quoted-string">'postId'</span> <span class="token operator">=></span> <span class="token class-name static-context">Yii</span><span class="token operator">::</span><span class="token variable">$app</span><span class="token operator">-></span><span class="token property">request</span><span class="token operator">-></span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'id'</span><span class="token punctuation">)</span><span class="token punctuation">]</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">]</span><span class="token punctuation">,</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h3 id="使用默认角色" tabindex="-1"><a class="header-anchor" href="#使用默认角色"><span>使用默认角色</span></a></h3>
<p>所谓默认角色就是 <em>隐式</em> 地指派给 <em>所有</em> 用户的角色。不需要调用 [[yii\rbac\ManagerInterface::assign()]] 方法做显示指派，并且授权数据中不包含指派信息。</p>
<p>默认角色通常与一个规则关联，用以检查该角色是否符合被检查的用户。</p>
<p>默认角色常常用于已经确立了一些角色的指派关系的应用（译者注：指派关系指的是应用业务逻辑层面， 并非指授权数据的结构）。比如，一个应用的 user 表中有一个 <code v-pre>group</code> 字段，代表用户属于哪个特权组。 如果每个特权组可以映射到 RBAC 的角色，你就可以采用默认角色自动地为每个用户指派一个 RBAC 角色。 让我们用一个例子展示如何做到这一点。</p>
<p>假设在 user 表中，你有一个 <code v-pre>group</code> 字段，用 1 代表管理员组，用 2 表示作者组。 你规划两个 RBAC 角色 <code v-pre>admin</code> 和 <code v-pre>author</code> 分别对应这两个组的权限。 你可以这样设置 RBAC 数据，</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">namespace</span> <span class="token package">app<span class="token punctuation">\</span>rbac</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Yii</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">yii<span class="token punctuation">\</span>rbac<span class="token punctuation">\</span>Rule</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token doc-comment comment">/**</span>
<span class="line"> * 检查是否匹配用户的组</span>
<span class="line"> */</span></span>
<span class="line"><span class="token keyword">class</span> <span class="token class-name-definition class-name">UserGroupRule</span> <span class="token keyword">extends</span> <span class="token class-name">Rule</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token keyword">public</span> <span class="token variable">$name</span> <span class="token operator">=</span> <span class="token string single-quoted-string">'userGroup'</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line">    <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">execute</span><span class="token punctuation">(</span><span class="token variable">$user</span><span class="token punctuation">,</span> <span class="token variable">$item</span><span class="token punctuation">,</span> <span class="token variable">$params</span><span class="token punctuation">)</span></span>
<span class="line">    <span class="token punctuation">{</span></span>
<span class="line">        <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span><span class="token class-name static-context">Yii</span><span class="token operator">::</span><span class="token variable">$app</span><span class="token operator">-></span><span class="token property">user</span><span class="token operator">-></span><span class="token property">isGuest</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">            <span class="token variable">$group</span> <span class="token operator">=</span> <span class="token class-name static-context">Yii</span><span class="token operator">::</span><span class="token variable">$app</span><span class="token operator">-></span><span class="token property">user</span><span class="token operator">-></span><span class="token property">identity</span><span class="token operator">-></span><span class="token property">group</span><span class="token punctuation">;</span></span>
<span class="line">            <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token variable">$item</span><span class="token operator">-></span><span class="token property">name</span> <span class="token operator">===</span> <span class="token string single-quoted-string">'admin'</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">                <span class="token keyword">return</span> <span class="token variable">$group</span> <span class="token operator">==</span> <span class="token number">1</span><span class="token punctuation">;</span></span>
<span class="line">            <span class="token punctuation">}</span> <span class="token keyword">elseif</span> <span class="token punctuation">(</span><span class="token variable">$item</span><span class="token operator">-></span><span class="token property">name</span> <span class="token operator">===</span> <span class="token string single-quoted-string">'author'</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">                <span class="token keyword">return</span> <span class="token variable">$group</span> <span class="token operator">==</span> <span class="token number">1</span> <span class="token operator">||</span> <span class="token variable">$group</span> <span class="token operator">==</span> <span class="token number">2</span><span class="token punctuation">;</span></span>
<span class="line">            <span class="token punctuation">}</span></span>
<span class="line">        <span class="token punctuation">}</span></span>
<span class="line">        <span class="token keyword">return</span> <span class="token constant boolean">false</span><span class="token punctuation">;</span></span>
<span class="line">    <span class="token punctuation">}</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>然后按 <a href="https://github.com/yiisoft/yii2/blob/master/docs/guide-zh-CN/security-authorization.md#generating-rbac-data" target="_blank" rel="noopener noreferrer">in the previous section</a> 中的说明创建自己的 command/migration：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$auth</span> <span class="token operator">=</span> <span class="token class-name static-context">Yii</span><span class="token operator">::</span><span class="token variable">$app</span><span class="token operator">-></span><span class="token property">authManager</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token variable">$rule</span> <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name class-name-fully-qualified"><span class="token punctuation">\</span>app<span class="token punctuation">\</span>rbac<span class="token punctuation">\</span>UserGroupRule</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token variable">$auth</span><span class="token operator">-></span><span class="token function">add</span><span class="token punctuation">(</span><span class="token variable">$rule</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token variable">$author</span> <span class="token operator">=</span> <span class="token variable">$auth</span><span class="token operator">-></span><span class="token function">createRole</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'author'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token variable">$author</span><span class="token operator">-></span><span class="token property">ruleName</span> <span class="token operator">=</span> <span class="token variable">$rule</span><span class="token operator">-></span><span class="token property">name</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token variable">$auth</span><span class="token operator">-></span><span class="token function">add</span><span class="token punctuation">(</span><span class="token variable">$author</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token comment">// ... 添加$author角色的子项部分代码 ... （译者注：省略部分参照之前的控制台命令）</span></span>
<span class="line"></span>
<span class="line"><span class="token variable">$admin</span> <span class="token operator">=</span> <span class="token variable">$auth</span><span class="token operator">-></span><span class="token function">createRole</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'admin'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token variable">$admin</span><span class="token operator">-></span><span class="token property">ruleName</span> <span class="token operator">=</span> <span class="token variable">$rule</span><span class="token operator">-></span><span class="token property">name</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token variable">$auth</span><span class="token operator">-></span><span class="token function">add</span><span class="token punctuation">(</span><span class="token variable">$admin</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token variable">$auth</span><span class="token operator">-></span><span class="token function">addChild</span><span class="token punctuation">(</span><span class="token variable">$admin</span><span class="token punctuation">,</span> <span class="token variable">$author</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token comment">// ... 添加$admin角色的子项部分代码 ... （译者注：省略部分参照之前的控制台命令）</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>注意，在上述代码中，因为 “author” 作为 “admin” 的子角色，当你实现这个规则的 <code v-pre>execute()</code> 方法时， 你也需要遵从这个层次结构。这就是为何当角色名为 “author” 的情况下（译者注：<code v-pre>$item-&gt;name</code>就是角色名）， <code v-pre>execute()</code> 方法在组为 1 或者 2 时均要返回 true （意思是用户属于 “admin” 或者 “author” 组 ）。</p>
<p>接下来，在配置 <code v-pre>authManager</code> 时指定 [[yii\rbac\BaseManager::$defaultRoles]] 选项（译者注：在应用配置文件中的组件部分配置）：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">return</span> <span class="token punctuation">[</span></span>
<span class="line">    <span class="token comment">// ...</span></span>
<span class="line">    <span class="token string single-quoted-string">'components'</span> <span class="token operator">=></span> <span class="token punctuation">[</span></span>
<span class="line">        <span class="token string single-quoted-string">'authManager'</span> <span class="token operator">=></span> <span class="token punctuation">[</span></span>
<span class="line">            <span class="token string single-quoted-string">'class'</span> <span class="token operator">=></span> <span class="token string single-quoted-string">'yii\rbac\PhpManager'</span><span class="token punctuation">,</span></span>
<span class="line">            <span class="token string single-quoted-string">'defaultRoles'</span> <span class="token operator">=></span> <span class="token punctuation">[</span><span class="token string single-quoted-string">'admin'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'author'</span><span class="token punctuation">]</span><span class="token punctuation">,</span></span>
<span class="line">        <span class="token punctuation">]</span><span class="token punctuation">,</span></span>
<span class="line">        <span class="token comment">// ...</span></span>
<span class="line">    <span class="token punctuation">]</span><span class="token punctuation">,</span></span>
<span class="line"><span class="token punctuation">]</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>现在如果你执行一个存取权限检查， 判定该规则时， <code v-pre>admin</code> 和 <code v-pre>author</code> 两个角色都将会检查。如果规则返回 true ，意思是角色符合当前用户。基于上述规则 的实现，意味着如果某用户的 <code v-pre>group</code> 值为 1 ， <code v-pre>admin</code> 角色将赋予该用户， 如果 <code v-pre>group</code> 值是 2 则将赋予 <code v-pre>author</code> 角色。</p>
<blockquote>
<p>💖喜欢本文档的，欢迎点赞、收藏、留言或转发，谢谢支持！<br>
作者邮箱：zhuzixian520@126.com，github地址：<a href="https://github.com/zhuzixian520" target="_blank" rel="noopener noreferrer">github.com/zhuzixian520</a></p>
</blockquote>
</div></template>


